
import fs from "fs";
import parser from '@babel/parser';
import traverse from '@babel/traverse';
import path from "path";
import ejs from "ejs";
import {transformFromAst} from "babel-core";
import {jsonLoader} from './jsonLoader.js';
import {ChangeOutputPath} from "./ChangeOutputPath.js";
import { SyncHook } from "tapable";

let id = 0;


const webpackConfig = {
    module: {
        rules: [
          {
            test: /\.json$/,
            use: [jsonLoader],
          }
        ]
      },
    plugins:[new ChangeOutputPath()],
}
const hooks = {
    emitFile:new SyncHook(["context"])
}
function createAsset(filePath){
    // 1. 获取文件的内容
   
    // ast -> 抽象语法树
    let source = fs.readFileSync(filePath,{
        encoding:"utf-8"
    });
    // initLoader
    const loaders = webpackConfig.module.rules
    const loaderContext = {
        addDeps(dep){
            console.log("addDeps",dep);
        }
    }
    loaders.forEach(({test,use})=>{
        
        if (test.test(filePath)){
            if (Array.isArray(use)){
                use.forEach((fn)=>{
                    source = fn.call(loaderContext,source);
                })
            } else {
                source = use(source);
            }
            
        }
    })

    // 2. 获取依赖关系
    const ast = parser.parse(source,{
        sourceType:"module",
    });
    // console.log(ast);
    const deps = [];
    traverse.default(ast,{
        ImportDeclaration({node}){
            
            deps.push(node.source.value);
        }
    })
    const {code} = transformFromAst(ast,null,{
        presets:["env"],
    })
    // console.log(code)
    return {
        source,
        deps,
        filePath,
        mapping:{},
        code,
        id:id++,
    }
}

// const asset = createAsset();
// console.log(asset);  

function createGraph(){
    const mainAsset = createAsset("./example/main.js");

    const queue = [mainAsset]

    for (const asset of queue){
        asset.deps.forEach(relativePath => {
            // console.log("example"+relativePath);
            const child = createAsset(path.resolve("./example",relativePath));
            asset.mapping[relativePath] = child.id;
            queue.push(child);
        });
        
    }
    return queue;
}
function initPlugins(){
    const plugins = webpackConfig.plugins;
    plugins.forEach((plugin)=>{
        plugin.apply(hooks);
    })
}
initPlugins()
const graph = createGraph();
// console.log(graph)

function build(graph){
    const template = fs.readFileSync("./bundle.ejs",{encoding:"utf-8"})
    
    const data = graph.map((asset)=>{
        const {id,code,mapping} = asset;
        return {
            code,
            id,
            mapping,
        }
    })

    const code = ejs.render(template,{data});
    let outputPath = "./dist/bundle.js";
    const context = {
        changeOutputPath(path){
            outputPath = path;
        }
    }
    hooks.emitFile.call(context)
    fs.writeFileSync(outputPath,code);
  
}

build(graph);